package com.google.code.smon.app;

import com.google.code.smon.pers.Server;
import com.google.code.smon.pers.ServerStatus;
import java.lang.reflect.Constructor;
import java.util.Random;
import java.util.logging.Logger;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

/**
 *
 * @author Simon Beckstein
 */
public class ServerMonitor extends Thread {

    private static final Logger log = Logger.getLogger(ServerMonitor.class.getName());
    /** How often the Thread checks the serverstatus in seconds */
    private int checkIntervall = 10;
    /** The Server Object to this Monitor */
    private Server server;
    /** The server type object that implements logic to check a server status */
    private ServerStatusHandler serverHandler;

    public ServerMonitor(Server server) throws StatusHandlerInstantiationException {
        super();
        this.server = server;
        this.setName(server.getName());
        serverHandler = loadServerHandler(server);
    }

    @Override
    public void run() {

        try {
            int sleep = new Random().nextInt((checkIntervall + 1) * 1000);
            sleep(sleep);
            log.fine("Monitor for " + server.getName() + " started with delay of " + sleep);
        } catch (InterruptedException ex) {
        }
        while (!isInterrupted()) {
            try {
                sleep(checkIntervall * 1000);
            } catch (InterruptedException e) {
            }

            boolean oldstatus = server.getServerStatus().getServiceStatus();
            long time = System.currentTimeMillis();
            boolean online = serverHandler.isOnline();
            long latency = System.currentTimeMillis() - time;
            ServerStatus status;
            if (server.getServerStatus() == null) {
                status = new ServerStatus(server.getId());
                server.setServerStatus(status);
            } else {
                status = server.getServerStatus();
            }
            status.setServiceStatus(online);
            status.setLatency(online ? (int) latency : -1);

            if (oldstatus != online) {
                log.info("Status for " + server.getName() + " changed from " + oldstatus + " to " + online);
            }
        }
        log.fine("Monitor for " + server.getName() + " stopped");

    }

    private ServerStatusHandler loadServerHandler(Server s) throws StatusHandlerInstantiationException {
        try {
            Class cl = Class.forName(s.getType().getClassname());
            Constructor constructor = cl.getConstructor(new Class[]{Server.class
                    });
            Object o = constructor.newInstance(s);
            return (ServerStatusHandler) o;
        } catch (ClassNotFoundException ex) {
            throw new StatusHandlerInstantiationException("ServerHandler does not exist for Server " + s, ex);
        } catch (InstantiationException ex) {
            throw new StatusHandlerInstantiationException("ServerHandler cannot be instantiated", ex);
        } catch (IllegalAccessException ex) {
            throw new StatusHandlerInstantiationException("No Permissions to load class " + s.getType().getClassname(), ex);
        } catch (Exception ex) {
            throw new StatusHandlerInstantiationException("ServerStatusHandler cannot be loaded", ex);
        }
    }

    public void persist(Object object) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("smon");
        EntityManager em = emf.createEntityManager();
        em.getTransaction().begin();
        try {
            em.persist(object);
            em.getTransaction().commit();
        } catch (Exception e) {
            e.printStackTrace();
            em.getTransaction().rollback();
        } finally {
            em.close();
        }
    }
}
